package ch.schlegl.fastsvn;

import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNDiffClient;
import org.tmatesoft.svn.core.wc.SVNRevision;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
import java.util.logging.Logger;

public class SvnClient {
    private Logger logger = Logger.getLogger("SvnClient");
    protected SVNRepository repository = null;
    List<String> rootUrls = new ArrayList<String>();

    protected static class SvnConfig {
        private Map<String, String> messagePatterns = new HashMap<String, String>();

        public Map<String, String> getMessagePatterns() {
            return messagePatterns;
        }

        public void addMessagePattern(String pattern, String link) {
            this.messagePatterns.put(pattern, link);
        }

        @Override
        public String toString() {
            return "SvnConfig{" +
                    "messagePatterns=" + messagePatterns +
                    '}';
        }
    }

    protected Map<String, SvnConfig> svnConfigsByConfigIdentifier = new HashMap<String, SvnConfig>();
    protected Map<String, SvnConfig> svnConfigsByUrl = new HashMap<String, SvnConfig>();

    public SvnClient() throws IOException {
        Properties props = new Properties();
        props.load(SvnNodesResource.class.getClassLoader().getResourceAsStream("config.properties"));
        for (String propName : props.stringPropertyNames()) {
            String[] propertyNameParts = propName.split("\\.");
            if (propertyNameParts.length > 1) {
                String repoConfigId = propertyNameParts[1];
                SvnConfig svnConfig = getConfig(repoConfigId);
                if (propName.endsWith(".url")) {
                    String rootUrl = (String) props.get(propName);
                    svnConfigsByUrl.put(rootUrl, svnConfig);
                    rootUrls.add(rootUrl);
                } else if (propName.contains(".pattern.")) {
                    String pattern = (String) props.get(propName);
                    String link = (String) props.get(propName.replace("pattern", "link"));
                    if(link != null && pattern != null) {
                        svnConfig.addMessagePattern(pattern, link);
                    } else {
                        logger.warning("failed to load pattern " + pattern + " -> " + link);
                    }
                }
            }
        }
        logger.info("loaded root urls: " + rootUrls);
        logger.info("loaded configs: " + svnConfigsByUrl);
    }

    private SvnConfig getConfig(String repoConfigId) {
        if(!svnConfigsByConfigIdentifier.containsKey(repoConfigId)) {
            SvnConfig config = new SvnConfig();
            svnConfigsByConfigIdentifier.put(repoConfigId, config);
        }
        return svnConfigsByConfigIdentifier.get(repoConfigId);
    }

    protected String findRootUrl(String id) {
        for (String rootUrl : rootUrls) {
            if (id.contains(rootUrl)) {
                return rootUrl;
            }
        }
        return "";
    }

    protected void ensureConnected(String id) throws SVNException {
        if (repository == null) {
            connect(findRootUrl(id));
        }
    }

    protected SVNRepository connect(String url) throws SVNException {
/*
		String name = "";
		String password = "";
*/
        SVNRepositoryFactoryImpl.setup();
        repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url));
/*
		ISVNAuthenticationManager authManager = SVNWCUtil
				.createDefaultAuthenticationManager(name, password);
		repository.setAuthenticationManager(authManager);
*/
        return repository;
    }

    public List<String> getDiff(String url, String revision) {
        SVNDiffClient diffClient = SVNClientManager.newInstance()
                .getDiffClient();
        ByteArrayOutputStream os = new ByteArrayOutputStream();

        try {
            long revLong = Long.parseLong(revision);
            diffClient.doDiff(SVNURL.parseURIEncoded(url),
                    SVNRevision.UNDEFINED, SVNRevision.create(revLong),
                    SVNRevision.create(revLong - 1), SVNDepth.INFINITY, true,
                    os);
        } catch (SVNException e) {
            e.printStackTrace(new PrintStream(os));
        }
        return Arrays.asList(os.toString().split("\n"));
    }
}
